package a02;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestApplicationContext {
    public static void main(String[] args) {
//        testClassPathXmlApplicationContext();
//        testAnnotationConfigApplicationContext();
        testAnnotationConfigServletWebServerApplicationContext();
    }


    /**
     * 最经典原始的Context。通过读取xml里配置的类和类以来的信息获得beanDefinition，不过现在这个基本很少用呢
     */
    public static void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans01.xml");
        Bean1 bean1 = context.getBean("bean1", Bean1.class);
        System.out.println(bean1.getBean2());
    }

    /**
     * 通过配置类来获取bean的信息，非web环境下，这个ApplicationContext也比较常用
     */
    public static void testAnnotationConfigApplicationContext(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigBean.class);
        Bean1 bean1 = context.getBean("bean1", Bean1.class);
        System.out.println(bean1.getBean2());
    }

    /**
     * 这里会启动web容器，程序开始监听请求
     */
    public static void testAnnotationConfigServletWebServerApplicationContext() {
        //注意不要写成AnnotationConfigServletWebApplicationContext,两个有点像
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }

    @Configuration
    static public class WebConfig{

        /**
         * web服务需要运行在web容器里面，我们最常用的web容器自然就是Tomcat。这里配置Tomcat容器工厂即可
         * 从这里我们也可以知道，springboot是内嵌了Tomcat的，而不需要我们一开始那样去手动配置tomcat的
         * 路径
         */
        @Bean
        public ServletWebServerFactory webServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        /**
         * springMVC中，DispatcherServlet是所有请求的入口，这个核心类的注入自然也必不可少
         */
        @Bean
        public DispatcherServlet dispatcherServlet(){
            return new DispatcherServlet();
        }

        /**
         * DispatcherServlet与容器关联。
         * DispatcherServletRegistrationBean继承自ServletRegistrationBean。我们在原始的web应用中，都是手动
         * 注册servlet的，这里这个ServletRegistrationBean应该也就是类似的作用呢
         */
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet servlet) {
            return new DispatcherServletRegistrationBean(servlet, "/");
        }

        /**
         * 为了便于测试web容器，我们这里写一个Controller。区别于我们平时通过@RequestMapping等写法的Controller，
         * 这里是直接实现一个Controller接口，把这个bean注入，本质都是一样的。
         * @return
         */
        @Bean("/hello")
        public Controller controller() {
            return new Controller() {
                @Override
                public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
                    response.getWriter().println("hello");
                    return null;
                }
            };
        }



    }


    @Configuration
    static class ConfigBean{

        @Bean
        public Bean1 bean1(){
            return new Bean1();
        }

        @Bean
        public Bean2 bean2(){
            return new Bean2();
        }

    }

    static class Bean1{

        public Bean2 getBean2() {
            return bean2;
        }

        public void setBean2(Bean2 bean2) {
            this.bean2 = bean2;
        }

        @Autowired
        Bean2 bean2;

    }

    static class Bean2{

    }



}
